package com.taobao.top.authorize;

import java.io.UnsupportedEncodingException;
import java.net.URL;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONObject;

import com.taobao.top.api.exception.ApiException;
import com.taobao.top.beans.AppConstants;
import com.taobao.top.beans.OAuth2;
import com.taobao.top.utils.TaobaoHttpClient;

/**
 * Top授权
 * 
 * @author <a href="http://weibo.com/shichaosong">Shichao Song</a>
 * @Data 2011-10-17
 * @QQ 421271944
 * @Version 1.0
 */
public class TaobaoAuthorize {
	private static Log log = LogFactory.getLog(TaobaoAuthorize.class);
	private TaobaoHttpClient taobaoHttpClient;

	/**
	 * 第一步：获取登陆URL接口
	 * 
	 * @return
	 * @throws Exception 
	 */
	public String getLoginUrl(String callbackUrl) throws Exception {
		taobaoHttpClient = new TaobaoHttpClient();

		String queryString = this.getLoginUrlParams(callbackUrl);
		log.info("requestToken queryString = " + queryString);
		System.out.println("queryString:" + queryString);

		String responseData = taobaoHttpClient.httpGet(queryString);
		log.info("requestToken responseData = " + responseData);
		System.out.println("responseData:" + responseData);

		String ret = "[" + "SUCCESS::调用成功" + "]";
		String result = parseLoginResponse(responseData);
		if (result == null && ret != result.substring(10, 14)) {
			log.info("获取登陆URL接口失败");
		}

		return parseLoginResponse(responseData);
	}

	/**
	 * 第一步：拼装登陆时的URL字符串
	 * <p>
	 * 如果用户输入了回调URL就在授权完毕后跳转到第三方的URL地址
	 * </p>
	 * 
	 * @return
	 */
	public String getLoginUrlParams(String callbackUrl) {
		String appSecret = AppConstants.SECRET;
		String api = "com.taobao.wireless.mtop.getLoginUrl";
		String data;
		if (callbackUrl != null && !callbackUrl.equals("")) {
			data = "{\"appkey\":\"" + AppConstants.APP_KEY + "\","
					+ "\"callbackUrl\":\"" + callbackUrl + "\"}";
		} else {
			data = "{\"appkey\":\"" + AppConstants.APP_KEY + "\"";
		}

		long t = System.currentTimeMillis() / 1000;
		String curTime = String.valueOf(t);

		String sign = getNoLoginSign(appSecret, api, "*", AppConstants.IMEI,
				AppConstants.IMSI, data, t);

		String strURL = "http://m.taobao.com/rest/api2.do?api="
				+ "com.taobao.wireless.mtop.getLoginUrl" + "&v=*" + "&imei="
				+ AppConstants.IMEI + "&imsi=" + AppConstants.IMSI + "&appkey="
				+ AppConstants.APP_KEY + "&ttid=" + AppConstants.TTID + "&t="
				+ curTime + "&sign=" + sign + "&data=" + data;

		log.info("strURL = " + strURL);
		return convertURL(strURL);
	}

	/**
	 * 我认为这里就是进行了一次URLEncoder.encode，对浏览器不支持的字符，取它的十六进制字符，以%--表示
	 * 
	 * @param str
	 * @return
	 */
	public static String convertURL(String str) {
		String url = null;
		try {
			url = new String(str
					.trim()
					// .replace(" ", "%20").replace("&", "%26")
					// .replace(",", "%2c").replace("(", "%28").replace(")",
					// "%29")
					// .replace("!", "%21").replace("=", "%3D").replace("<",
					// "%3C")
					// .replace(">", "%3E").replace("#", "%23").replace("$",
					// "%24")
					// .replace("'", "%27").replace("*", "%2A").replace("-",
					// "%2D")
					// .replace(".", "%2E").replace("/", "%2F").replace(":",
					// "%3A")
					// .replace(";", "%3B").replace("?", "%3F").replace("@",
					// "%40")
					// .replace("[", "%5B").replace("\\", "%5C").replace("]",
					// "%5D")
					// .replace("_", "%5F").replace("`", "%60").replace("|",
					// "%7C")
					.replace("\"", "%22").replace("{", "%7B")
					.replace("}", "%7D"));
		} catch (Exception e) {
			e.printStackTrace();
		}

		log.info("convertURL strURL = " + url);
		return url;
	}

	/**
	 * 未登录：md5(appSecret+api+v+imei+imsi+md5(data)+t)如果涉及到编码请使用gbk编码进行加
	 * 
	 * @param appSecret
	 * @param api
	 * @param v
	 * @param imei
	 * @param imsi
	 * @param data
	 * @param time
	 * @return
	 */
	public String getNoLoginSign(final String appSecret, final String api,
			final String v, final String imei, final String imsi,
			final String data, final long time) {
		try {
			return DigestUtils.md5Hex((appSecret + api + v + imei + imsi
					+ DigestUtils.md5Hex(data.getBytes("GBK")) + time)
					.getBytes("GBK"));
		} catch (UnsupportedEncodingException e) {
		}
		return null;
	}

	/**
	 * 已登录：md5(ecode + appSecret+api+v+imei+imsi+md5(data)+t)如果涉及到编码请使用gbk编码进行加
	 * 
	 * @param ecode
	 * @param appSecret
	 * @param api
	 * @param v
	 * @param imei
	 * @param imsi
	 * @param data
	 * @param time
	 * @return
	 */
	public String getLoginSign(final String ecode, final String appSecret,
			final String api, final String v, final String imei,
			final String imsi, final String data, final long time) {
		try {
			return DigestUtils.md5Hex((ecode + appSecret + api + v + imei
					+ imsi + DigestUtils.md5Hex(data.getBytes("GBK")) + time)
					.getBytes("GBK"));
		} catch (UnsupportedEncodingException e) {
		}
		return null;
	}

	/**
	 * 第二步：获取会话接口
	 */
	public String getUserSessionKey(OAuth2 oauth) throws Exception {
		taobaoHttpClient = new TaobaoHttpClient();

		String queryString = getUserSessionKeyParams();
		log.info("getUserSessionKey queryString = " + queryString);

		String responseData = taobaoHttpClient.httpGet(queryString);
		log.info("responseData = " + responseData);

		String ret = "[" + "SUCCESS::调用成功" + "]";
		String result = parseLoginResponse(responseData);
		if (result == null && ret != result.substring(10, 14)) {
			log.info("获取用户会话失败");
		}

		return parseLoginResponse(responseData);
	}

	/**
	 * 第二步：5.2:获取会话接口参数
	 */
	public String getUserSessionKeyParams() {
		String serverUrl = "http://m.taobao.com/rest/api2.do";
		String api = "com.taobao.client.mtop.getUserSessionKey";
		String v = AppConstants.v;
		String imei = AppConstants.IMEI;
		String imsi = AppConstants.IMSI;
		String ttid = AppConstants.TTID;
		String appKey = AppConstants.APP_KEY;
		String appSecret = AppConstants.SECRET;
		String data = "{\"key\":\"" + AppConstants.LOGINKEY + "\","
				+ "\"appkey\":\"" + AppConstants.APP_KEY + "\"}";
		long t = System.currentTimeMillis() / 1000;
		String curTime = String.valueOf(t);
		String sign = getNoLoginSign(appSecret, api, "*", AppConstants.IMEI,
				AppConstants.IMSI, data, t);

		String strURL = serverUrl + "?api=" + api + "&v=" + v + "&imei=" + imei
				+ "&imsi=" + imsi + "&appkey=" + appKey + "&ttid=" + ttid
				+ "&t=" + curTime + "&sign=" + sign + "&data=" + data;

		log.info("getUserSessionKey url = " + strURL);
		return convertURL(strURL);
	}

	/**
	 * 获取账户资料,并且转换成User实例
	 * 
	 * @param oauth
	 * @return
	 * @throws Exception
	 */
	// public User getUser(OAuth2 oauth) throws Exception {
	// User user = new User();
	//
	// String myInfo = (new User_API()).info(oauth, "xml");
	//
	// SAXReader saxReader = new SAXReader();
	// Document xml = saxReader.read(new
	// ByteArrayInputStream(myInfo.getBytes("UTF-8")));
	//
	// int ret = Integer.parseInt(xml.selectSingleNode("root/ret").getText());
	// if (ret != 0) {
	// return user;
	// }
	//
	// String name = xml.selectSingleNode("root/data/name").getText();
	// String nick = xml.selectSingleNode("root/data/nick").getText();
	// String head = xml.selectSingleNode("root/data/head").getText();
	// String isvip = xml.selectSingleNode("root/data/isvip").getText();
	// String sex = xml.selectSingleNode("root/data/sex").getText();
	// String fansnum = xml.selectSingleNode("root/data/fansnum").getText();
	// String idolnum = xml.selectSingleNode("root/data/idolnum").getText();
	// String tweetnum = xml.selectSingleNode("root/data/tweetnum").getText();
	//
	// user.setNick(nick);
	// user.setSex(sex);
	//
	// return user;
	// }

	/**
	 * 解析第二步返回的SessionKey
	 */
	public String parseSessionKeyResponse(String response) throws Exception {
		if (response == null || response.equals("")) {
			return null;
		}

		JSONObject data;
		data = new JSONObject(response);
		String ret = data.getString("ret");
		JSONObject urlData = data.getJSONObject("data");
		String topsession = urlData.getString("topsession");
		String sid = urlData.getString("sid");
		String time = urlData.getString("time");
		String ecode = urlData.getString("ecode");
		String nick = urlData.getString("nick");
		String token = urlData.getString("token");

		// 赋值为常量
		AppConstants.SID = sid;
		AppConstants.ECODE = ecode;
		AppConstants.NICK = nick;
		AppConstants.TOKEN = token;
		AppConstants.TOPSESSION = topsession;

		return ret.substring(10, 14);
	}

	/**
	 * 解析第一步获取登陆URL返回的信息
	 * 
	 * @param response
	 * @param oauth
	 * @return
	 * @throws Exception
	 */
	public String parseLoginResponse(String response) throws Exception {
		if (response == null || response.equals("")) {
			return null;
		}

		JSONObject data;
		data = new JSONObject(response);
		String ret = data.getString("ret");
		JSONObject urlData = data.getJSONObject("data");
		String url = urlData.getString("url");
		String key = urlData.getString("key");

		// 赋值为常量
		AppConstants.LOGINURL = url;
		AppConstants.LOGINKEY = key;

		return ret.substring(10, 14);
	}

	/**
	 * 解析第三步自动登陆返回的信息
	 * 
	 * @param response
	 * @param oauth
	 * @return
	 * @throws Exception
	 */
	public String parseAutoLoginResponse(String response) throws Exception {
		if (response == null || response.equals("")) {
			return null;
		}

		JSONObject data;
		data = new JSONObject(response);
		String ret = data.getString("ret");
		JSONObject urlData = data.getJSONObject("data");
		String topsession = urlData.getString("topSession");
		String sid = urlData.getString("sid");
		String ecode = urlData.getString("ecode");
		String logintime = urlData.getString("logintime");
		String userId = urlData.getString("userId");

		// 赋值为常量
		AppConstants.SID = sid;
		AppConstants.ECODE = ecode;
		AppConstants.TOPSESSION = topsession;
		AppConstants.USERID = userId;

		return ret.substring(10, 14);
	}

	/**
	 * 第三步：自动登陆接口
	 */
	public String getAutoLogin(OAuth2 oauth) throws Exception {
		taobaoHttpClient = new TaobaoHttpClient();

		String queryString = getAutoLoginParams();
		log.info("getAutoLogin queryString = " + queryString);

		String responseData = taobaoHttpClient.httpGet(queryString);
		log.info("responseData = " + responseData);

		String ret = "[" + "SUCCESS::调用成功" + "]";
		String result = parseLoginResponse(responseData);
		if (result == null && ret != result.substring(10, 14)) {
			log.info("自动登陆失败");
		}

		return parseLoginResponse(responseData);
	}

	/**
	 * 第三步：自动登录
	 */
	public String getAutoLoginParams() {
		String serverUrl = "http://m.taobao.com/rest/api2.do";
		String api = "com.taobao.client.sys.autologin";
		String v = AppConstants.v;
		String imei = AppConstants.IMEI;
		String imsi = AppConstants.IMSI;
		String ttid = AppConstants.TTID;
		String appKey = AppConstants.APP_KEY;
		String appSecret = AppConstants.SECRET;
		long t = System.currentTimeMillis() / 1000;
		String curTime = String.valueOf(t);
		String ecode = AppConstants.ECODE;
		String nick = AppConstants.NICK;
		// toptoken计算规则：md5(appKey+md5(appSecret)+nick+t)
		String topToken = genLoginTopToken(nick, appSecret, appKey, t);
		String data = "{\"token\":\"" + AppConstants.TOKEN + "\","
				+ "\"appKey\":\"" + AppConstants.APP_KEY + "\","
				+ "\"topToken\":\"" + topToken + "\"}";
		String sign = getLoginSign(ecode, appSecret, api, v, imei, imsi, data,
				t);

		String strURL = serverUrl + "?api=" + api + "&v=*" + "&imei=" + imei
				+ "&imsi=" + imsi + "&appkey=" + appKey + "&ttid=" + ttid
				+ "&t=" + curTime + "&sign=" + sign + "&data=" + data;

		log.info("strURL = " + strURL);
		return convertURL(strURL);
	}

	/**
	 * 第三步计算toptoken用的 产生topToken String
	 * md5(appKey+md5(appSecret)+nick+t)，所有字段都是GBK编码
	 * 
	 * @param nick
	 * @param appSec
	 * @param appKey
	 * @param time
	 * @return
	 */
	public String genLoginTopToken(final String nick, final String appSec,
			final String appKey, final long time) {
		try {
			return DigestUtils.md5Hex((appKey
					+ DigestUtils.md5Hex(appSec.getBytes("GBK")) + nick + time)
					.getBytes("GBK"));
		} catch (UnsupportedEncodingException e) {
		}
		return null;
	}

	/**
	 * 处理请求URL
	 * 
	 * @param url
	 * @return
	 */
	private static String getNormalizedUrl(URL url) {
		try {
			StringBuilder buf = new StringBuilder();
			buf.append(url.getProtocol());
			buf.append("://");
			buf.append(url.getHost());
			if ((url.getProtocol().equals("http") || url.getProtocol().equals(
					"https"))
					&& url.getPort() != -1) {
				buf.append(":");
				buf.append(url.getPort());
			}
			buf.append(url.getPath());
			return buf.toString();
		} catch (Exception e) {
		}
		return null;
	}

}
